package com.zyl.blog.common.utils.Extreme;

import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.function.Function;
import java.util.regex.Pattern;

/**
 * 敏感数据脱敏工具类
 *
 * <p>功能说明：</p>
 * <ul>
 *   <li>支持字符串直接脱敏</li>
 *   <li>支持对象属性批量脱敏（基于Getter/Setter）</li>
 *   <li>内置常见数据类型脱敏策略</li>
 *   <li>支持自定义脱敏规则</li>
 * </ul>
 *
 * @version v1.0
 * @ProjectName: Personal_Blog
 * @Package: com.zyl.common.utils.Extreme
 * @ClassName: DataDesensitizationUtils
 * @Description: 敏感数据脱敏工具类
 * @Author FinalFantasy
 * @Date 2025/3/8-17:42
 */
public class DataDesensitizationUtils {

    // 预编译正则表达式
    private static final Pattern CHINESE_NAME_PATTERN = Pattern.compile("([\\u4e00-\\u9fa5]{2})(.*)");
    private static final Pattern MOBILE_PATTERN = Pattern.compile("(\\d{3})\\d{4}(\\d{4})");
    private static final Pattern ID_CARD_PATTERN = Pattern.compile("(\\d{6})\\d{8}([\\dXx]{4})");
    private static final Pattern EMAIL_PATTERN = Pattern.compile("(.{1,2}).*(@.{1,10}\\..+)");
    private static final Pattern MOBILE_VALIDATION = Pattern.compile("^1[3-9]\\d{9}$");

    /**
     * 脱敏策略注解
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    public @interface Desensitize {
        Class<?> strategyClass() default Void.class;
        String strategy() default "";
    }

    /**
     * 通用脱敏方法
     */
    public static <T> T desensitize(T source, DesensitizationStrategy<T> strategy) {
        if (source == null) return null;
        return strategy.apply(source);
    }

    /**
     * 脱敏策略接口
     */
    @FunctionalInterface
    public interface DesensitizationStrategy<T> extends Function<T, T> {
        @Override
        T apply(T data);
    }

    /**
     * 预定义脱敏策略
     */
    public static class Strategies {
        /**
         * 中文姓名脱敏（欧阳*）
         */
        public static final DesensitizationStrategy<String> CHINESE_NAME = data -> {
            Assert.hasText(data, "Name cannot be empty");
            return CHINESE_NAME_PATTERN.matcher(data).replaceAll("$1*");
        };

        /**
         * 手机号脱敏（138****5678）
         */
        public static final DesensitizationStrategy<String> MOBILE = data -> {
            Assert.isTrue(MOBILE_VALIDATION.matcher(data).matches(), "Invalid mobile number");
            return MOBILE_PATTERN.matcher(data).replaceAll("$1****$2");
        };

        /**
         * 身份证号脱敏（110123********1234）
         */
        public static final DesensitizationStrategy<String> ID_CARD = data -> {
            Assert.isTrue(data.matches("\\d{17}[\\dXx]"), "Invalid ID card");
            return ID_CARD_PATTERN.matcher(data).replaceAll("$1********$2");
        };

        /**
         * 邮箱脱敏（ab***@domain.com）
         */
        public static final DesensitizationStrategy<String> EMAIL = data -> {
            Assert.isTrue(data.contains("@"), "Invalid email");
            return EMAIL_PATTERN.matcher(data).replaceAll("$1***$2");
        };

        /**
         * 自定义固定长度脱敏
         */
        public static DesensitizationStrategy<String> fixedLength(int prefixKeep, int suffixKeep, char maskChar) {
            return data -> {
                if (data == null) return null;
                int minLength = prefixKeep + suffixKeep + 1;
                Assert.isTrue(data.length() >= minLength,
                        "Data length must ≥ " + minLength + ", actual: " + data.length());

                String prefix = data.substring(0, prefixKeep);
                String suffix = data.substring(data.length() - suffixKeep);
                return prefix + String.valueOf(maskChar).repeat(data.length() - prefixKeep - suffixKeep) + suffix;
            };
        }
    }

    /**
     * 深度对象脱敏（基于反射）
     */
    public static <T> T deepDesensitize(T obj) {
        if (obj == null) return null;

        ReflectionUtils.doWithFields(obj.getClass(), field -> {
            if (!field.isAnnotationPresent(Desensitize.class)) return;

            field.setAccessible(true);
            Desensitize annotation = field.getAnnotation(Desensitize.class);
            Object value = field.get(obj);
            if (value instanceof String) {
                field.set(obj, applyStrategy((String) value, annotation));
            }
        });

        return obj;
    }

    /**
     * 深度脱敏（无注解版本）
     * @param obj 目标对象
     * @param fieldStrategyMap 字段名与脱敏策略的映射
     * @return 脱敏后的对象
     */
    public static <T> T deepDesensitize(T obj, Map<String, DesensitizationStrategy<String>> fieldStrategyMap) {
        if (obj == null || fieldStrategyMap == null) return obj;

        ReflectionUtils.doWithFields(obj.getClass(), field -> {
            DesensitizationStrategy<String> strategy = fieldStrategyMap.get(field.getName());
            if (strategy != null && field.getType() == String.class) {
                field.setAccessible(true);
                String original = (String) field.get(obj);
                field.set(obj, strategy.apply(original));
            }
        });

        return obj;
    }

    private static String applyStrategy(String data, Desensitize annotation) {
        try {
            if (!annotation.strategyClass().equals(Void.class)) {
                Field strategyField = annotation.strategyClass().getDeclaredField(annotation.strategy());
                return convertStrategy(strategyField).apply(data);
            }
            // 其他策略解析逻辑...
        } catch (Exception e) {
            throw new RuntimeException("Desensitization strategy error", e);
        }
        return data;
    }

    @SuppressWarnings("unchecked")
    private static DesensitizationStrategy<String> convertStrategy(Field field)
            throws IllegalAccessException {

        Object raw = field.get(null);
        if (raw instanceof DesensitizationStrategy) {
            return (DesensitizationStrategy<String>) raw;
        }
        throw new ClassCastException("Invalid strategy type: " + raw.getClass());
    }

    /**
     * 批量集合脱敏
     */
    public static <T> Collection<T> batchDesensitize(Collection<T> collection,
                                                     DesensitizationStrategy<T> strategy) {
        Assert.notNull(collection, "Collection must not be null");
        Collection<T> result = new ArrayList<>(collection.size());
        for (T item : collection) {
            result.add(desensitize(item, strategy));
        }
        return result;
    }
}